﻿#define _CRT_SECURE_NO_WARNINGS 1
#pragma once

#include <iostream>
#include <fstream>
#include <sstream>
#include "log.hpp"
#include "configreader.hpp"
#include <regex>

using namespace std;

//static const int MAX_LINE = 1024;

class MarkdownTransform
{
public:
	//MarkdownTransform()
	//	:_filename("nullptr"), _openDolDete(false) {}
	MarkdownTransform(const string& filename, const string& openDolDete)
		:_filename(filename), _openDolDete(openDolDete == "true" ? true : false) {}
	string parseInLine(string line)
	{
		string outbuffer = line;

		// 1.图片
		regex imgRegex(R"(!\[([^\]]*)\]\((\s*"[^"]*"|\s*'[^']*'|\s*[^'"\s)]*)(\s+"[^"]*"|\s*'[^']*'|\s*[^'"\s)]*)?\s*\))");
		outbuffer = std::regex_replace(outbuffer, imgRegex, R"(<img src="$2" alt="$1" title="$4">)");

		// 2.链接
		regex link_regex(R"(\[([^\[\]]*)\]\((\s*([^)\s"]*)(\s+"[^"]*")?\s*)\))");
		outbuffer = regex_replace(outbuffer, link_regex, "<a href=\"$2\" title=\"$3\">$1</a>");


		// 3.加粗
		std::regex boldRegex(R"(\*\*(.*?)\*\*|__(.*?)__)");
		outbuffer = regex_replace(outbuffer, boldRegex, R"(<strong>$1$2</strong>)");

		// 4.斜体
		std::regex italicRegex(R"(\*([^\*]+)\*)");
		outbuffer = regex_replace(outbuffer, italicRegex, R"(<em>$1$2</em>)");

		// 5.删除线
		std::regex deleteRegex(R"(~~([^~]+)~~)");
		outbuffer = regex_replace(outbuffer, deleteRegex, R"(<del>$1$2</del>)");

		//// 6.单个'$'
		//std::regex oneMathRegex(R"(\$\$([\s\S)*?)\$\$)");
		//outbuffer = regex_replace(outbuffer, oneMathRegex, R"(<script type=\"text/math/tex; mode=display\">$1</script>)");

		//// 6.'$$'
		//std::regex towMathRegex(R"((?<!\\)\$([^\\$]*?)\$(?!\$))");
		//outbuffer = regex_replace(outbuffer, towMathRegex,[](const smatch& m)
		//	{string formula = m[1].str();regex escapeRegex(R"(\\\$)");
		//	formula = regex_replace(formula, escapeRegex, "$");
		//	return "<script type=\"text/math/tex\">" + formula + "</script>";});

		return outbuffer;
	}
	void getLineOfResource(string &inbuffer, vector<string> &lines)
	{
		if (!inbuffer.empty())
		{
			stringstream ss(inbuffer);
			string line;
			while (getline(ss, line)) lines.push_back(line);
		}
		else
		{
			logMessage(WARNING, "inbuffer is empty!!!");
			exit(4);cin.get();
		}
	}
	string convertContToHtml(vector<string> &lines)
	{
		string htmlContent;
		bool inUnorderedList = false;
		bool inOrderedList = false;
		int inCodeBlock = 0;
		bool dbDolType = false;
		bool oneDolType = false;
		for (auto &line : lines)
		{
			// 去除首位空格
			size_t first = line.find_first_not_of(" ");
			if (first == string::npos) line.clear();
			else
			{
				line.erase(0, first);
				line.erase(line.find_last_not_of("\t") + 1);
			}

			if(_openDolDete)
			{
				// 处理'$' 与"$$"
				size_t dblDolPos = line.find("$$");
				while (dblDolPos != string::npos)
				{
					if (!dbDolType)
					{
						line.replace(dblDolPos, 2, "<script type=\"text/math/tex\">");
						dbDolType = true;
					}
					else
					{
						line.replace(dblDolPos, 2, "</script>");
						dbDolType = false;
					}dblDolPos = line.find("$$");
				}
				size_t oneDolPos = line.find("$$");
				while (oneDolPos != string::npos)
				{
					if (!oneDolType)
					{
						line.replace(oneDolPos, 1, "<script type=\"text/math/tex\">");
						oneDolType = true;
					}
					else
					{
						line.replace(oneDolPos, 1, "</script>");
						oneDolType = false;
					}oneDolPos = line.find("$");
				}
			}

			// 5.代码块
			string codeType;
			size_t codeBlockFirst = line.find("```");
			if (line == "```")
				string acout = "";

			if (codeBlockFirst == 0)
			{
				if (inCodeBlock) 
				{
					inCodeBlock = 0;
					htmlContent += "</span></code></pre>";
					continue;
				}
				line.erase(0, 3);
				// 删空格
				size_t first = line.find_first_not_of(" ");
				if (first == string::npos) line.clear();
				else line.erase(0, first);
				if (line.empty())
				{
					codeType = "code-highlight";
					htmlContent += "<pre><code class=\"code-highlight\">";
				}
				else
				{
					codeType = line;
					htmlContent += "<pre class=\"language-" + codeType + "\">" + "<code class=\"language-" + codeType + " code-highlight\">";
				}
				inCodeBlock = 1;
				//tryAddCodeBlock(inCodeBlock, htmlContent, line);
				continue;
			}
			else if (tryAddCodeBlock(inCodeBlock, htmlContent, line)) continue;

			// 1.空行
			if (line.empty())
			{
				tryCloseUnorderList(inUnorderedList, htmlContent);
				tryCloseOrderList(inOrderedList, htmlContent);
				htmlContent += "\n";
				continue;
			}

			// 2.标题
			smatch titleMatch;
			if (regex_match(line, titleMatch, regex(R"(^(#+)\s+(.*)$)")))
			{
				tryCloseUnorderList(inUnorderedList, htmlContent);
				tryCloseOrderList(inOrderedList, htmlContent);
				int level = titleMatch[1].str().size();
				htmlContent += "<h" + to_string(level) + ">" + parseInLine(titleMatch[2].str())+"</h"+to_string(level) + ">\n";
				continue;
			}

			// 3.无序列表
			smatch ulMatch;
			if (regex_match(line, ulMatch, regex(R"(^(-|\*)\s+(.*)$)")))
			{
				tryCloseOrderList(inOrderedList, htmlContent);
				string liContent(parseInLine(ulMatch[2].str()));
				if (!inUnorderedList)
				{
					htmlContent += "<ul>\n";
					inUnorderedList = true;
				}
				htmlContent += "<li>" + liContent + "</li>\n";
				continue;
			}

			// 4.有序列表
			smatch olMatch;
			if (regex_match(line, olMatch, regex(R"(^(\d+)\.\s+(.*)$)")))
			{
				tryCloseUnorderList(inUnorderedList, htmlContent);
				string olContent(parseInLine(olMatch[2].str()));
				if (!inOrderedList)
				{
					htmlContent += "<ol>\n";
					inOrderedList = true;
				}
				htmlContent += "<li>" + olContent + "</li>\n";
				continue;
			}

			// 其他普通段落
			tryCloseUnorderList(inUnorderedList, htmlContent);
			tryCloseOrderList(inOrderedList, htmlContent);
			if (line.find("---") == 0)// 在开头就找到了"---"
			{htmlContent += "<hr>\n";continue;}

			htmlContent += "<p>" + parseInLine(line) + "</p>\n";
		}
		// 如果还有未关闭的无序列表
		tryCloseUnorderList(inUnorderedList, htmlContent);
		tryCloseOrderList(inOrderedList, htmlContent);
		if(_openDolDete)
		{
			tryCloseDolList(dbDolType, htmlContent);
			tryCloseDolList(oneDolType, htmlContent);
		}
		if (htmlContent.empty()) cout << "哎呀，这个文件里空空如也呀～也许可以换个有内容的 Markdown 文件来转成 HTML 试试哦" << char(3);
		cout << htmlContent << endl;

		return htmlContent;
	}
	void getMarkdownResource(string &inbuffer)
	{
		ifstream inFile(_filename);
		if (!inFile.is_open())
		{
			logMessage(FATAL, "fail open file: %s\n", _filename.c_str());
			exit(3);cin.get();
		}
		// 1.使用string的迭代器来范围读取
		//return string(istreambuf_iterator<char>(inFile), istreambuf_iterator<char>());
		inbuffer = string(istreambuf_iterator<char>(inFile), istreambuf_iterator<char>());
		if (inbuffer.empty()) logMessage(ERROR, "file: %s is empty!!!\n", _filename.c_str());
	}
	void getContents(string &outbuffer)
	{
	}
	~MarkdownTransform()
	{
	}
private:
	bool tryAddCodeBlock(int& inCodeBlock, string &htmlContent, string &line)
	{
		if (inCodeBlock == 1)
		{
			htmlContent += "<span class=\"code-line line-number\" line=\"" + to_string(inCodeBlock++) + "\">" + line + "\n";
			return true;
		}
		if (inCodeBlock > 1)
		{
			htmlContent += "</span><span class=\"code-line line-number\" line=\"" + to_string(inCodeBlock++) + "\">" + line + "\n";
			return true;
		}
		return false;
	}
	void tryCloseUnorderList(bool& inUnorderedList, string &htmlContent)
	{
		if (inUnorderedList)
		{
			htmlContent += "</ul>\n";
			inUnorderedList = false;
		}
	}	
	void tryCloseOrderList(bool& inOrderedList, string& htmlContent)
	{
		if (inOrderedList)
		{
			htmlContent += "</ol>\n";
			inOrderedList = false;
		}
	}
	void tryCloseDolList(bool& DolType, string& htmlContent)
	{
		if (DolType)
		{
			htmlContent += "</script>\n";
			DolType = false;
		}
	}
private:
	bool _openDolDete;
	string _filename;
};